package com.yuw.threaddemo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 仓库栈
 */
public class MyStack {
    // 栈使用数组来进行存储
    // 属性
    // 存储数组
    private Goods[] goodsStack;
    // 栈顶指针
    private int index;
    // 仓库栈的容量【数组的长度】
    private int stackCount;

    // Lock接口锁的使用
    private Lock lock; // 等价于 synchronized 关键字的用法
    // 获取枷锁条件对象
    private Condition condition;  // 等价于 Object类的 wait-notify 机制

    // 行为

    public MyStack(int stackCount, Lock lock, Condition condition) {
        this.stackCount = stackCount;
        // 初始化栈信息
        // 仓库容量不能为负值
        if (this.stackCount <= 0) {
            // 默认仓库容量为10
            this.stackCount = 10;
        }
        goodsStack = new Goods[this.stackCount];
        // 设置栈顶指针初始位置
        index = 0;

        this.lock = lock;
        this.condition = condition;
    }

    // 入栈

    /**
     * 入栈操作
     *
     * @param good 入栈的商品
     */
    public void push(Goods good) {
        // 将产品存入当前栈顶位置
        // 枷锁
        lock.lock();
        try {
            // 当仓库满的时候，让生产者自行挂起，生产者自动进入仓库的等待队列，等待消费者去消费仓库的商品
            if (index >= stackCount) {
                //this.wait(); // 调用wait方法，当前生产者线程自动进入 挂起的等待队列，线程不再执行
                // 进入阻塞队列
                condition.await(); // 等价于Object类的 wait方法 进入 挂起 状态
            }
            // 如果仓库没有满，则继续生产产品入库，同时通知在仓库的消费者等待队列可以进行消费了
            goodsStack[index] = good;
            // 存入之后，栈顶位置向上移动一个单元
            index++;
            System.out.println("生产者生产了一个商品。。。");
            // 通知消费者等待队列可以消费了
            //this.notifyAll();
            condition.signalAll(); // 等价于 Object类的 notifyAll

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    // 出栈

    /**
     * 出栈操作
     *
     * @return 当前栈顶位置的商品对象
     */
    public Goods pop() {
        // 默认返回值
        Goods goods = null;
        // 枷锁
        lock.lock();
        try {
            // 当仓库空的时候，让消费者自行挂起，消费者自动进入仓库的等待队列，等待生产者去生产仓库的商品
            if (index <= 0) {
                //this.wait(); // 调用wait方法，当前消费者线程自动进入 挂起的等待队列，线程不再执行
                // 进入阻塞队列
                condition.await(); // 等价于Object类的 wait方法 进入 挂起 状态
            }

            // 栈顶位置向下移动一个单元
            index--;
            // 取出当前位置的商品
            goods = goodsStack[index];
            // 将当前栈顶位置置空
            goodsStack[index] = null;
            System.out.println("消费者消费了一个商品。。。");
            // 如果仓库没有空，则继续消费产品出库，同时通知在仓库的生产者等待队列可以去生产了
            // 通知生产者等待队列的线程，可以进行生产了
            //this.notifyAll();
            condition.signalAll(); // 等价于 Object类的 notifyAll

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
        }
        // 返回栈顶元素
        return goods;
    }
}
